#include "FlowManager.h"
#include "md5.h"

#include <iostream>

FlowManager *FlowManager::mInstance = nullptr;
std::mutex FlowManager::mInstanceMutex;


int CreateBufferFlowId(int size, int count)
{
	return FlowManager::getInstance()->CreateFlowId(size, count);
}

void FreeBufferFlowId(int flow_id)
{
	FlowManager::getInstance()->DestoryFlowId(flow_id);
}

int WriteDataToBufferFlow(int flow_id, char *data, int size)
{
    return FlowManager::getInstance()->WriteDataToFlow(flow_id, data, size);
}

int ReadDataFromBufferFlow(int flow_id, char *data, int size, int* post)
{
    return FlowManager::getInstance()->ReadDataFromFlow(flow_id, data, size, post);
}

FlowManager *FlowManager::getInstance()
{
    if (mInstance == nullptr)
    {
        std::unique_lock<std::mutex> lock(mInstanceMutex);
        if (mInstance == nullptr)
        {
            mInstance = new FlowManager();
            return mInstance;
        }
    }
    return mInstance;
}

FlowManager::FlowManager()
    : mFlowCounter(0)
{
}

FlowManager::~FlowManager()
{
    for (auto it = mUMap.begin(); it != mUMap.end(); ++it)
    {
        if (it->second.flow != nullptr)
        {
            rbuf_destroy(it->second.flow);
        }
    }
    mUMap.clear();
}

rflow_t *FlowManager::GetRflowByFlowId(int flow_id)
{
    auto it = mUMap.find(flow_id);
    if (it != mUMap.end())
    {
        return it->second.flow;
    }
    return nullptr;
}

int FlowManager::CreateFlowId(int size, int count)
{
    int flowId;
    std::string md5;
    flow_node node;
    rflow_t *flow_buf = rbuf_create(nullptr, size, count, RBUF_MODE_SIMPLE, 0);
    if (!flow_buf)
    {
        std::cerr << "rbuf create failed, can't create flow id" << std::endl;
        return FLOW_BUF_CREATE_FAILED;
    }

    flowId = (size << 24) | (count << 16) | (++mFlowCounter);
    md5 = MD5(std::to_string(flowId)).toStr();
    node = {flow_buf, size, count, flowId, 0, 0};
    snprintf(node.media_id, sizeof(node.media_id), "%s", md5.c_str());

    while (GetRflowByFlowId(flowId))
    {
        flowId++;
        node.flow_id = flowId;
    }
    mUMap.insert(std::make_pair(flowId, node));

    return flowId;
}

void FlowManager::DestoryFlowId(int flow_id)
{
    auto it = mUMap.find(flow_id);
    if (it != mUMap.end())
    {
        rbuf_destroy(it->second.flow);
        mUMap.erase(flow_id);
    }
}

int FlowManager::IsvalidFlowId(int flow_id)
{
    rflow_t *flow_buf = GetRflowByFlowId(flow_id);
    return flow_buf ? 0 : -1;
}

int FlowManager::WriteDataToFlow(int flow_id, char *data, int size)
{
    rflow_t *flow_buf = GetRflowByFlowId(flow_id);
    if (!flow_buf)
    {
        std::cerr << "no find flow bufffer" << std::endl;
        return FLOW_BUF_NOT_FOUND;
    }
    return rbuf_write(flow_buf, data, size);
}

int FlowManager::WriteDataToFlow(rflow_t *flow, char *data, int size)
{
    return rbuf_write(flow, data, size);
}

int FlowManager::ReadDataFromFlow(int flow_id, char *data, int size, int *post)
{
    rflow_t *flow_buf = GetRflowByFlowId(flow_id);
    if (!flow_buf)
    {
        std::cerr << "no find flow bufffer" << std::endl;
        return FLOW_BUF_NOT_FOUND;
    }
    return rbuf_read_post(flow_buf, data, size, post);
}

char *FlowManager::GetMediaId(int flow_id)
{
    auto it = mUMap.find(flow_id);
    if (it != mUMap.end())
    {
        return it->second.media_id;
    }
    return nullptr;
}